﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;

namespace Isotop.Text
{
	public class VStringBase
	{
		/// <summary>
		/// Note! Mark any calling method with [SecurityCritical]
		/// </summary>
		protected static Func<int, string> FastAllocateString;
		protected static FieldInfo ChunkCharsField;

		static VStringBase()
		{
			var methodInfo = typeof(string).GetMethod("FastAllocateString", BindingFlags.Static | BindingFlags.NonPublic, null, CallingConventions.Any, new[] { typeof(int) }, null);

			//If not dynamic method is used, it will hang 5th time (???)
			DynamicMethod fAllocStr = new DynamicMethod("fAllocStr", typeof(string), new[] { typeof(int) }, typeof(string).Module, true);

			ILGenerator il = fAllocStr.GetILGenerator();
			il.Emit(OpCodes.Ldarg_0);
			il.EmitCall(OpCodes.Call, methodInfo, null);
			il.Emit(OpCodes.Ret);
			fAllocStr.DefineParameter(1, ParameterAttributes.In, "length");

			FastAllocateString = (Func<int, string>)fAllocStr.CreateDelegate(typeof(Func<int, string>));

			ChunkCharsField = typeof (StringBuilder).GetField("m_ChunkChars", BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);
		}

		protected static unsafe void wstrcpy(char* dmem, char* smem, int charCount)
		{
			if (charCount > 0)
			{
				if ((((int)dmem) & 2) != 0)
				{
					dmem[0] = smem[0];
					dmem++;
					smem++;
					charCount--;
				}
				while (charCount >= 8)
				{
					*((uint*)dmem) = *((uint*)smem);
					*((uint*)(dmem + 2)) = *((uint*)(smem + 2));
					*((uint*)(dmem + 4)) = *((uint*)(smem + 4));
					*((uint*)(dmem + 6)) = *((uint*)(smem + 6));
					dmem += 8;
					smem += 8;
					charCount -= 8;
				}
				if ((charCount & 4) != 0)
				{
					*((uint*)dmem) = *((uint*)smem);
					*((uint*)(dmem + 2)) = *((uint*)(smem + 2));
					dmem += 4;
					smem += 4;
				}
				if ((charCount & 2) != 0)
				{
					*((uint*)dmem) = *((uint*)smem);
					dmem += 2;
					smem += 2;
				}
				if ((charCount & 1) != 0)
				{
					dmem[0] = smem[0];
				}
			}
		}
	}
}
